#pragma once
#include <iostream>
#include <assert.h>
#include "QueueAbs.h"

using namespace std;

template<class Type>
struct node
{
	Type elem;
	node<Type>* next;
};

template<class Type>
class QueueLink:public QueueAbs<Type>
{
public:
	 bool isEmpty()const ;
	 bool isFull()const ;
	 void initializeQueue() ;
	 Type front()const ;
	 Type back()const ;
	 void addElem(const Type&) ;
	 void deleteElem() ;
	 int queueLen()const ;
	 QueueLink();
	 QueueLink(const QueueLink<Type>&);
	 ~QueueLink();
	 const QueueLink<Type>& operator=(const QueueLink<Type>&);
private:
	node<Type>* head;
	node<Type>* tail;
	int length;
	void copyQueue(const QueueLink<Type>&);
};

template<class Type>
bool QueueLink<Type> ::isEmpty()const
{
	return head == nullptr;
}

template<class Type>
bool QueueLink<Type> ::isFull()const
{
	return false;
}

template<class Type>
void QueueLink<Type>::initializeQueue()
{
	node<Type>* temp = head;
	while (head)
	{
		head = head->next;
		delete temp;
		temp = head;
	}
	tail = nullptr;
	length = 0;
}

template<class Type>
Type QueueLink<Type>::front()const
{
	assert(!isEmpty());
	return head->elem;
}

template<class Type>
Type QueueLink<Type>::back()const
{
	assert(!isEmpty());
	return tail->elem;
}

template<class Type>
void QueueLink<Type>::addElem(const Type& elem)
{
	node<Type>* newNode = new node<Type>;
	newNode->elem = elem;
	newNode->next = nullptr;
	if (head == nullptr)
	{
		tail = newNode;
		head = newNode;
	}
	else
	{
		tail->next = newNode;
		tail = tail->next;
	}
	length++;
}

template<class Type>
void QueueLink<Type>::deleteElem()
{
	if (!isEmpty())
	{
		node<Type>* temp = head;
		head = head->next;
		delete temp;
		length--;
	}
	else
		cout << "The queue is empty,cannot remove an element" << endl;
}

template<class Type>
int QueueLink<Type>::queueLen()const
{
	return length;
}

template<class Type>
QueueLink<Type>::QueueLink()
{
	head = nullptr;
	tail = head;
	length = 0;
}

template<class Type>
QueueLink<Type>::~QueueLink()
{
	initializeQueue();
}

template<class Type>
void QueueLink<Type>::copyQueue(const QueueLink<Type>& otherQueue)
{
	node<Type>* temp,otherCurrent;
	otherCurrent = otherQueue.head;
	if (head)
		initializeQueue();
	if (otherQueue.head)
	{
		head = new node<Type>;
		tail = head;
		head->elem = otherCurrent->elem;
		head->next = otherCurrent->next;
		otherCurrent = otherCurrent->next;
		length++;
		while (otherCurrent)
		{
			temp = new node<Type>;
			temp->next = otherCurrent->next;
			temp->elem = otherCurrent->elem;
			tail->next = temp;
			tail = tail->next;
			otherCurrent = otherCurrent->next;
			length++;
		}
	}
}

template<class Type>
QueueLink<Type>::QueueLink(const QueueLink<Type>& otherQueue)
{
	copyQueue(otherQueue);
}

template<class Type>
const QueueLink<Type>& QueueLink<Type>::operator=(const QueueLink<Type>& otherQueue)
{
	if (this != &otherQueue)
	{
		copyQueue(otherQueue);
	}
	return *this;
}

